<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>5.着色器实现像素动画-非线性插值(贝塞尔曲线缓动)</title>
    <style>
        canvas{
            border:1px solid #aaa;
            margin: 0 auto;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="554" height="554"></canvas>
    <script src="/common/lib/gl-renderer.js"></script>

    <script type="module">
        import { loadImage, toPolar, fromPolar } from "/common/lib/utils.js";
        import {Animator} from '/common/lib/animator.js';
        

        /**
         * gl-renderer五步法
         * 1.创建renderer对象
         * 2.创建并启用webgl程序
         * 3.设置uniform变量
         * 4.将定点数据送入缓冲区
         * 5.渲染
         * 
        */
        // 1.
        let canvas = document.querySelector("canvas");
        const renderer = new GlRenderer(canvas);

        // 2.
        const vertex = `
            attribute vec2 a_vertexPosition;
            attribute vec2 uv;
            varying vec2 vUv;

            void main(){
                gl_PointSize = 1.0;
                vUv = uv;
                gl_Position = vec4(a_vertexPosition, 1.0, 1.0);
            }
        `
        // 
        const fragment = `
            #ifdef GL_ES
            precision highp float;
            #endif
            varying vec2 vUv;
            uniform vec4 uFromcolor;
            uniform vec4 uTocolor;

            float slope_from_t (float t, float A, float B, float C){
                float dtdx = 1.0/(3.0*A*t*t + 2.0*B*t + C); 
                return dtdx;
            }

            float x_from_t (float t, float A, float B, float C, float D){
                float x = A*(t*t*t) + B*(t*t) + C*t + D;
                return x;
            }

            float y_from_t (float t, float E, float F, float G, float H){
                float y = E*(t*t*t) + F*(t*t) + G*t + H;
                return y;
            }

            float cubic_bezier (float x, float a, float b, float c, float d){
                float y0a = 0.00; // initial y
                float x0a = 0.00; // initial x 
                float y1a = b;    // 1st influence y   
                float x1a = a;    // 1st influence x 
                float y2a = d;    // 2nd influence y
                float x2a = c;    // 2nd influence x
                float y3a = 1.00; // final y 
                float x3a = 1.00; // final x 

                float A = x3a - 3.0 *x2a + 3.0 * x1a - x0a;
                float B = 3.0 * x2a - 6.0 * x1a + 3.0 * x0a;
                float C = 3.0 * x1a - 3.0 * x0a;   
                float D = x0a;

                float E = y3a - 3.0 * y2a + 3.0 * y1a - y0a;    
                float F = 3.0 * y2a - 6.0 * y1a + 3.0 * y0a;             
                float G = 3.0 * y1a - 3.0 * y0a;             
                float H = y0a;

                // Solve for t given x (using Newton-Raphelson), then solve for y given t.
                // Assume for the first guess that t = x.
                float currentt = x;
                const int nRefinementIterations = 5;
                for (int i=0; i < nRefinementIterations; i++){
                    float currentx = x_from_t(currentt, A,B,C,D); 
                    float currentslope = slope_from_t(currentt, A,B,C);
                    currentt -= (currentx - x)*(currentslope);
                    currentt = clamp(currentt, 0.0, 1.0);
                } 

                float y = y_from_t(currentt, E,F,G,H);
                return y;
            }

            void main() {
                vec2 uv = vUv;
                float p = cubic_bezier( uv.x, 2.0, 5.0, 4.0, 0.0);
                vec4 d = mix(uFromcolor, uTocolor, p);
                gl_FragColor = d;
            }
        `
        const program = renderer.compileSync(fragment, vertex);
        renderer.useProgram(program);

        renderer.uniforms.uFromcolor = [1.0, 0.0, 0.0, 1.0];
        renderer.uniforms.uTocolor = [0.0, 0.5, 0.6, 1.0];
        
        renderer.setMeshData([{
            positions: [
                [-1, -1],
                [-1, 1],
                [1, 1],
                [1, -1],
            ],
            attributes: {
                uv: [
                    [0, 0],
                    [0, 1],
                    [1, 1],
                    [1, 0],
                ],
            },
            cells: [[0, 1, 2], [2, 0, 3]],
        }]);
        renderer.render();

    </script>
</body>
</html>